/*
 * @Description: 主进程：在这个文件中，你可以包括你的应用程序的特定主进程代码的其余部分。
 * 您也可以将它们放在单独的文件中，并在这里导入它们。
 * @Date: 2024-02-01 09:43:37
 * @FilePath: \demod:\12electron\electron-demo\src\main\index.ts
 */
import { app, shell, BrowserWindow, ipcMain, Notification, dialog, Tray, Menu, nativeImage } from 'electron';
import { join } from 'path';
import { spawn } from 'child_process';
import { electronApp, optimizer, is } from '@electron-toolkit/utils';
import icon from '../../resources/icon.png?asset';
import { getSerialPortList, creatSerialPortConnection, sendSerialPortData } from './serialport';

import { SerialPort } from 'serialport';
import './modbus-serial'; // 引入自定义rs485串口modbus工具
import './file'; // 引入自定义文件处理工具

function sysNotice(title, body) {
  new Promise((ok, fail) => {
    if (!Notification.isSupported()) fail('当前系统不支持通知');

    const ps = typeof title == 'object' ? title : { title, body };
    const n = new Notification(ps);
    n.on('click', ok);
    n.show();
  });
}

// 打开文件目录
async function handleFileOpen() {
  const { canceled, filePaths } = await dialog.showOpenDialog({
    properties: ['openFile'],
    // filters: [{ name: 'Executable Files', extensions: ['exe'] }]
  });
  // 如果选择了文件，并且没有取消
  if (!canceled) {
    const filePath = filePaths[0];
    // 确保路径有效并尝试执行
    if (filePath.endsWith('.exe')) {
      console.log(filePath);
    } else {
      sysNotice('余浩提示', '您没有选择exe程序');
    }
    return filePath;
  } else {
    sysNotice('余浩提示', '您取消了选择');
    return null;
  }
}

function handleExecute(_event, path) {
  console.log(path);
  // const webContents = event.sender
  // const win = BrowserWindow.fromWebContents(webContents)
  // 执行简单的、返回结果较小的命令，或者你的命令依赖于shell特性
  // const res = exec(path, (error, stdout, stderr) => {
  //   if (error) {
  //     console.error(`执行出错: ${error}`)
  //     return
  //   }
  //   // 输出子进程的标准输出
  //   console.log(`stdout: ${stdout}`)
  //   // 输出子进程的错误输出
  //   console.error(`stderr: ${stderr}`)
  // })

  // 处理大体积的输出、交互式地读写子进程的输入输出流，或者想要更多的控制权
  const res = spawn(path);
  // win.setTitle(title)
  console.log(res);
}

// 创建窗口
let mainWindow: any = null;
const createWindow = () => {
  mainWindow = new BrowserWindow({
    width: 900,
    height: 670,
    show: false,
    autoHideMenuBar: true,
    ...(process.platform === 'linux' ? { icon } : {}),
    webPreferences: {
      //  预加载脚本在渲染器进程加载之前加载，并有权访问两个 渲染器全局 (例如 window 和 document) 和 Node.js 环境。
      preload: join(__dirname, '../preload/index.js'),
      sandbox: false,
      webSecurity: false, // 保持启用,
      allowRunningInsecureContent: true, // 安全策略  https://www.electronjs.org/zh/docs/latest/tutorial/security
    },
  });

  mainWindow.on('ready-to-show', () => {
    mainWindow.show();
  });

  mainWindow.webContents.setWindowOpenHandler((details) => {
    shell.openExternal(details.url);
    return { action: 'deny' };
  });

  // HMR for renderer base on electron-vite cli.
  // Load the remote URL for development or the local html file for production.
  if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
    mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL']);
  } else {
    mainWindow.loadFile(join(__dirname, '../renderer/index.html'));
  }
};

// 创建最小化托盘
const creatTray = () => {
  let tray;
  app.whenReady().then(() => {
    const trayIcon = nativeImage.createFromPath(icon); // 托盘图标
    tray = new Tray(trayIcon);

    const contextMenu = Menu.buildFromTemplate([
      // {
      //   label: '开始',
      //   type: 'normal',
      //   click: startRecording
      // },
      // {
      //   label: '停止',
      //   type: 'normal',
      //   click: stopRecording
      // },
      { label: '测试按钮1', type: 'radio' },
      { label: '测试按钮2', type: 'radio' },
      { type: 'separator' },
      { label: '退出', type: 'normal', role: 'quit' },
    ]);

    tray.setContextMenu(contextMenu);
    tray.setToolTip('余浩的桌面应用程序');
  });
};

// 当Electron完成初始化并准备创建浏览器窗口时，将调用此方法。有些api只能在此事件发生后使用。
app.whenReady().then(() => {
  SerialPort.list()
    .then((ports) => {
      ports.forEach((port) => console.log(port.path));
    })
    .catch((error) => {
      console.error('Error listing ports:', error);
    });

  // 设置windows应用的用户模型id
  electronApp.setAppUserModelId(process.execPath);

  // 在开发中默认使用F12打开或关闭DevTools，而在生产中忽略commandcontrol + R
  // see https://github.com/alex8088/electron-toolkit/tree/master/packages/utils
  app.on('browser-window-created', (_, window) => {
    optimizer.watchWindowShortcuts(window);
  });

  // IPC进程间通信测试
  ipcMain.on('ping', () => console.log('pong'));
  ipcMain.on('sysMsg', () => {
    sysNotice('系统通知', '测试消息');
  });
  // 监听事件:IPC 通道名称上的 dialog: 前缀对代码没有影响。 它仅用作命名空间以帮助提高代码的可读性。
  ipcMain.handle('dialog:openFile', handleFileOpen);

  // 单向通信：执行程序
  ipcMain.on('exe:execute', handleExecute);

  // 获取串口列表
  ipcMain.on('serialport:getSerialPortList', async (event, _data) => {
    console.log('_data: ', _data);
    const result = await getSerialPortList();
    // 将数据发送回渲染进程
    event.reply('serialport:getSerialPortList:reply', result);
  });

  // 创建串口连接
  ipcMain.on('serialport:creatSerialPortConnection', async (event, data) => {
    creatSerialPortConnection(data)
      .then((res) => {
        event.reply('serialport:creatSerialPortConnection:reply', res);
        sysNotice('创建串口连接成功', '创建串口:' + res + '连接成功');
      })
      .catch((err: any) => {
        sysNotice('创建串口连接失败', err);
      });
  });

  // 发送串口数据
  ipcMain.on('serialport:sendData', (_event, data) => {
    console.log(data);
    sendSerialPortData(data.path, data.data);
  });

  createWindow(); // 创建窗口
  creatTray(); // 创建托盘图标

  app.on('activate', function () {
    // 对macOSch创建窗口的判断
    if (BrowserWindow.getAllWindows().length === 0) createWindow();
  });
});

// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});
